// 参考： https://threejsfundamentals.org/threejs/lessons/threejs-post-processing.html
import { 
  AmbientLight,
  Color,
  Mesh,
  MeshPhongMaterial,
  Object3D,
  PerspectiveCamera,
  Scene, 
  SphereGeometry, 
  SpotLight, 
  TextureLoader, 
  Vector2, 
  Vector3, 
  WebGLRenderer,
} from "three";
import stats from '../utils/stats';
// 调用
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
import { ClearMaskPass, MaskPass } from 'three/examples/jsm/postprocessing/MaskPass';
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";
import { SepiaShader } from 'three/examples/jsm/shaders/SepiaShader';
import { ColorifyShader } from 'three/examples/jsm/shaders/ColorifyShader';
import { CopyShader } from "three/examples/jsm/shaders/CopyShader";
import { GUI } from "dat.gui";

let renderer = setRenderer();
// 注意 删除默认自动更新，否则无法查看合成效果
renderer.autoClear = false;

let camera = setCamera();
let textureLoader = new TextureLoader();


// 创建场景
let sceneEarth = new Scene();
let sceneMars = new Scene();
let sceneBG = new Scene();

// 
sceneBG.background = textureLoader.load('/textures/bg/starry-deep-outer-space-galaxy.jpg');
let earthAndLight = addEarth(sceneEarth);
sceneEarth.translateX(-16);
sceneEarth.scale.set(1.2, 1.2, 1.2);
let marsAndLight = addMars(sceneMars);
sceneMars.translateX(12);
sceneMars.translateY(6);
sceneMars.scale.set(0.2, 0.2, 0.2);

let bgRendererPass = new RenderPass(sceneBG, camera);
let earthRenderPass = new RenderPass(sceneEarth, camera);
earthRenderPass.clear = false;
let marsRenderPass = new RenderPass(sceneMars, camera);
marsRenderPass.clear = false;

// 使用掩膜
let clearMask = new ClearMaskPass();
let earthMask = new  MaskPass(sceneEarth, camera);
let marsMask = new MaskPass(sceneMars, camera);


let effectSepia = new ShaderPass(SepiaShader);
effectSepia.uniforms.amount.value = 0.8;
let effectColorify = new ShaderPass(ColorifyShader);
effectColorify.uniforms.color.value.setRGB(0.5, 0.5, 1);

let controls = {
  amount: 0.8,
  color: 0xffffff
}
let gui = new GUI()
let ssFolder = gui.addFolder('SepiaShader')
ssFolder.add(controls, 'amount', 0, 10).onChange(val => {
  effectSepia.uniforms.amount.value = val
});
let cFolder = gui.addFolder('ColorifyShader')
cFolder.addColor(controls, 'color').onChange(val => {
  effectColorify.uniforms.color.value.set(val)
})

let effectCopy = new ShaderPass(CopyShader);
effectCopy.renderToScreen = true;

let composer = new EffectComposer(renderer);
composer.renderTarget1.stencilBuffer = true;
composer.renderTarget2.stencilBuffer = true;
composer.addPass(bgRendererPass);
composer.addPass(earthRenderPass);
composer.addPass(marsRenderPass);

composer.addPass(marsMask);
composer.addPass(effectColorify);
composer.addPass(clearMask);

composer.addPass(earthMask);
composer.addPass(effectSepia);
composer.addPass(clearMask);

composer.addPass(effectCopy);


const trackballControls = new OrbitControls(camera, renderer.domElement);
render();
function render() {
  stats.update();
  trackballControls.update();

  earthAndLight.earth.rotation.y += 0.001;
  marsAndLight.mars.rotation.y += 0.01;

  requestAnimationFrame(render);
  composer.render();
}


function setRenderer() {
  const renderer = new WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 支持阴影生成 
  renderer.shadowMap.enabled = true;
  document.body.appendChild(renderer.domElement);

  return renderer
}

function setCamera(): PerspectiveCamera {
  let camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.set(0, 20, 40);

  return camera;
}


function addEarth(scene: Scene) {
  let textureLoader = new TextureLoader();
  let planetMaterial = new MeshPhongMaterial({
    map: textureLoader.load("/textures/earth/Earth.png"),
    normalMap: textureLoader.load("/textures/earth/EarthNormal.png"),
    specularMap: textureLoader.load("/textures/earth/EarthSpec.png"),
    specular: new Color(0x4444aa),
    normalScale: new Vector2(6,6),
    shininess: 0.5
  });
  
  let earth = new Mesh(new SphereGeometry(15, 40, 40), planetMaterial);
  scene.add(earth);
  var pivot = new Object3D();
  initDefaultLighting(pivot);
  scene.add(pivot);

  return {earth, pivot};
}

function initDefaultLighting(scene: any, initialPosition?: any) {
  let position = (initialPosition !== undefined) ? initialPosition : new Vector3(-10, 30, 40);
  
  let spotLight = new SpotLight(0xffffff);
  spotLight.position.copy(position);
  spotLight.shadow.mapSize.width = 2048;
  spotLight.shadow.mapSize.height = 2048;
  spotLight.shadow.camera.fov = 15;
  spotLight.castShadow = true;
  spotLight.decay = 2;
  spotLight.penumbra = 0.05;
  spotLight.name = "spotLight"

  let ambientLight = new AmbientLight(0x343434);
  ambientLight.name = "ambientLight";
  
  scene.add(spotLight);
  scene.add(ambientLight);  
}

function addMars(scene: Scene) {
  let textureLoader = new TextureLoader();
  let planetMaterial = new MeshPhongMaterial({
    map: textureLoader.load("/textures/mars/mars_1k_color.jpg"),
    // normalMap: textureLoader.load("/textures/mars/mars_1k_normal.jpg"),
    normalScale: new Vector2(6,6),
    shininess: 0.5
  });
  
  let mars = new Mesh(new SphereGeometry(15, 40, 40), planetMaterial);
  scene.add(mars);
  let pivot = new Object3D();
  initDefaultLighting(pivot);
  scene.add(pivot);

  return {mars, pivot};
}
